## plan:
## An xml file hold 2 lists, one of jobs to run & one of jobs which have been
##   completed. The script checks the list to decide which file to run next, and
##   transfers items to the completed list when the simulation ends, also adding
##   any extra information such as start & end times. Once a simulation job has
##   been opened, using subprocess, the runner returns to the command menu.



import subprocess       # For starting FDTD jobs
import os               # For interactingwith the filesystem
import xml.dom.minidom  # For xml documents
import time             # For start/end times
import random           # For testing
import createsamplelist # For testing

simulator = "..\\batch\\placeholder.bat"

# My ListReader class
class ListReader:
    """Executes an external program or batch file for each of a list of files
    contained in an xml specification"""
    time_format="%d/%m/%Y %X";
    def __init__(self,path):
        self._path = path;
        self._xmldoc = xml.dom.minidom.Document();
        self._statinfo = os.stat(self._path);
        self._goflag=False;
        self._procflag=False;
        self.readxml();
        return
    def start(self):
        if not self._goflag:
            self._goflag=True;
            self.processlist();
        else:
            print "ListReader for", self._path, "is already running!";
    def stop(self):
        if self._goflag:
            self._goflag=False;
            print "ListReader for", self._path, "will stop on completion of job", self._currentjob.getAttribute("file");
        else:
            print "ListReader for", self._path, "is already stopped!";
    def currentjob(self):
        return self._currentjob.cloneNode(True);
    def readxml(self):
        newinfo = os.stat(self._path);
#        print "re-checking xml";
        self._xmldoc = xml.dom.minidom.parse(self._path);
        self._stripjunk(self._xmldoc);
        # get blocks together
        self._aggregate("torun");
        self._aggregate("succeeded");
        self._aggregate("failed");
        # adjust current running item
        self._writecurrentjob();
        return
    def _stripjunk(self,node):
        dellist=list();
        for child in node.childNodes:
            if child.nodeType in (xml.dom.Node.TEXT_NODE,):
                dellist.append(child);
            else:
                self._stripjunk(child);
        for item in dellist:
            item.parentNode.removeChild(item);
        return None
    def writexml(self):
#        print "writing new xml"
        _fileobj=open(self._path,"w");
        _fileobj.write(self._xmldoc.toprettyxml());
        _fileobj.close();
        return
    
    def _writecurrentjob(self):
        self._aggregate("current",True);
        # select the "current" tag in the document, creating it if it doesn't
        # yet exist
        try:
            curr_el = self._xmldoc.getElementsByTagName("current")[0];
        except IndexError:
            curr_el = self._xmldoc.createElement("current");
            self._xmldoc.childNodes[0].appendChild(curr_el);
        # add the current job into the <current> tag
        try:
            curr_el.appendChild(self._currentjob);
        except AttributeError:
            pass
        return

    def _currentjobfinished(self,success):
        # Read xml first, to check for any new jobs that were added while we
        # were running the one we've just finished
        self.readxml();
        # Write data to the finished job
        self._currentjob.setAttribute("endtime",time.strftime(ListReader.time_format));
        # Move finished job from the current to the appropriate
        # completed list
        self._currentjob.parentNode.removeChild(self._currentjob);
        if success:
            listname="succeeded";
        else:
            listname="failed";
        self._xmldoc.getElementsByTagName(listname)[0].appendChild(self._currentjob);
        # Write modified data to xml.
        self.writexml();
        return

    def _picknextjob(self):
        newjob = self._xmldoc.getElementsByTagName("torun")[0].getElementsByTagName("FDTDjob")[0];
        newjob.parentNode.removeChild(newjob);
        self._currentjob = newjob;
        self._xmldoc.getElementsByTagName("current")[0].appendChild(self._currentjob);
        return self._currentjob.cloneNode(True);

    def _aggregate(self,elementname,empty=False):
        allelements = self._xmldoc.getElementsByTagName(elementname);
        if allelements.length>0:
            if empty:
                start=0;
            else:
                start=1;
            for element in allelements[start:allelements.length]:
                while element.childNodes.length:
                    if empty:                        
                        element.childNodes[0].parentNode.removeChild(element.childNodes[0]);
                    else:
                        # add child to the first "elementname" element
                        allelements[0].appendChild(element.childNodes[0]);
                # remove the element from the document tree
                element.parentNode.removeChild(element);
        else:
            # create an element of the appropriate name.
            allelements=[self._xmldoc.createElement(elementname)];
            self._xmldoc.childNodes[0].appendChild(allelements[0]);
        return allelements[0];

    def jobswaiting(self):
        return self._xmldoc.getElementsByTagName("torun")[0].getElementsByTagName("FDTDjob").length

    def processjob(self):        
        self._picknextjob();
        self._currentjob.setAttribute("starttime",time.strftime(ListReader.time_format));
        self.writexml();
        
        newproc = subprocess.Popen(os.path.abspath(simulator+" "+self._currentjob.getAttribute("file")),0,None,None,subprocess.PIPE);
##        counter = 0;
##        while not self._procflag:
##            tmr = threading.Timer(3, self._getinput);
##            tmr.start();
##            print newproc.poll()
##            if counter==9
##                self._procflag=True;
##            
        newproc.wait();
        print newproc.communicate()[0].replace("\r","");
        return bool(random.randint(0,1));        

    def processlist(self):
        while self.jobswaiting()>0:
            #print self.jobswaiting();
            success=self.processjob();
            #raw_input("this is a pause, ok?");
            self._currentjobfinished(success);

    def getmenu(self):
        done=False;
        while not done:
            if msvcrt.kbhit():
                letter=msvcrt.getche();
                if ord(letter)==13:
                    print("\nline return");
                else:
                    if letter=="Q":
                        done=True;
                    msvcrt.ungetch(letter);

#createsamplelist.refresh_list_file(1,10);
#raw_input("This is the first pause, ok?");
xmllist = ListReader("fdtd-jobs-list.xml");
#xmllist.processlist();
xmllist.getmenu();
